﻿#include "Matrix.h"
#include "Constant.h"
#include "CoordSys.h"
#include "TimeSys.h"
#include "ReadN.h"
#include "ReadO.h"
#include "GNSSSatPos.h"
#include <iostream>
#include <iomanip>
#include <vector>
#include <cstdlib> 
#include "LonosphereCorrection.h"
#include "TroposphereCorrection.h"
#include "PointPositioning.h"

using namespace std;

int main() {
    /* 测试常数类 */
    // 定义GNSS常数类指针
    GNSSconsts* pGnssConst;
    // 创建北斗系统常数类对象
    BDSConsts bdsConst;
    // 输出北斗系统参考椭球的扁率
    cout << fixed << bdsConst.get_refEllip().f << endl;

    /* 测试矩阵类 */
    // 输出测试矩阵类的提示信息
    cout << "/* 测试矩阵类 */" << endl;
    // 创建矩阵类对象
    Matrix matTest;
    // 调用矩阵类的测试函数
    matTest.test();

    /* 测试坐标系统类 */
    // 输出测试坐标系统类的提示信息
    cout << "/* 测试坐标系统类 */" << endl;
    // 定义坐标系统类指针
    CoordSys* pCoordSys;
    // 创建北斗坐标系统类对象，传入北斗系统参考椭球参数
    BDCS bdcs(bdsConst.get_refEllip());
    // 让指针指向北斗坐标系统类对象
    pCoordSys = &bdcs;
    // 调用坐标系统类的测试函数
    pCoordSys->test();

    /* 测试时间系统类 */
    // 输出测试时间系统类的提示信息
    cout << "/* 测试时间系统类 */" << endl;
    // 定义日历时间结构体，初始化为N文件中的第一个观测时间
    CalendT t = { 2017, 3, 7, 5, 6, 35.0 }; /* N 文件中的第一个观测时间 */
    // 创建北斗时间类对象
    BDSTime mBDST;
    // 定义时间系统类指针，指向北斗时间类对象
    TimeSys* pTimeSys = &mBDST;
    // 输出日历时间
    pTimeSys->print_time(t);
    cout << " 对应的BDS时间为：" << endl;
    // 将日历时间转换为周内秒
    SOW t2 = pTimeSys->calend2sow(t);
    // 输出周内秒
    pTimeSys->print_time(t2);

    /* 测试 Read N 文件类 */
    // 创建读取N文件类对象，传入N文件路径
    cout << "/* 测试Read N 文件类 */" << endl;
    ReadN mReadN("C://1234560660442.17N");
    // 解析N文件，若解析失败则退出程序
    if (!mReadN.parseFile()) return false;
    // 输出星历信息，若打印失败则退出程序
    if (!mReadN.print_eph()) return false;

    /* 测试 Read O 文件类 */
    // 定义O文件路径
    cout << "/* 测试Read O 文件类 */" << endl;
    string filename = "C://1234560660442.17O"; // 要读取的文件路径   
    // 创建读取O文件类对象，传入O文件路径
    ReadO mReadO(filename);  // 创建 ReadO 对象
    // 解析O文件，若解析失败则退出程序
    if (!mReadO.parse_file()) return false;
    // 输出O文件头信息
    mReadO.print_head(); // 显示文件头信息
    // 输出前2个观测历元的观测数据
    mReadO.print_body(2); // 显示前 2 个观测元的观测数据
    // 获取观测历元向量的指针
    vector<obsEpoch>* mObs = mReadO.get_obs();
    // 将O文件中第一个观测历元的时间转换为基准时间
    BaseT tr = pTimeSys->str2baseT(mObs->at(0).time); // 获取O文件中的第一个观测时间

    /* 测试卫星位置计算类 */
    // 输出测试卫星位置计算类的提示信息
    cout << "/* 测试卫星位置计算类 */" << endl;
    // 定义卫星位置计算类指针
    GNSSSatPos* pSatPos;
    // 创建北斗卫星位置计算类对象，传入时间系统类指针和读取N文件类对象指针
    BDSSatPos mBDSSatPos(pTimeSys, &mReadN);
    // 让指针指向北斗卫星位置计算类对象
    pSatPos = &mBDSSatPos; /* 让函数指针指向实际的对象 */
    // 定义卫星坐标结构体
    XYZ ps1;
    // 计算C01卫星在指定时间的位置
    ps1 = pSatPos->get_satPos("C01", tr);
    // 输出C01卫星的位置
    printf("C01 卫星位置:X=%.3f m, Y=%.3f m, Z=%.3f m\n", ps1.x, ps1.y, ps1.z);

    /* 测试电离层延迟误差改正类 */
    // 输出测试电离层延迟误差改正类的提示信息
    cout << "/* 测试电离层延迟误差改正类 */" << endl;
    // 创建电离层延迟误差改正类对象
    LonosphereCorrection ionoCorrection;
    // 调用电离层延迟误差改正类的测试函数
    ionoCorrection.test();

    /* 测试对流层延迟误差改正类 */
    // 输出测试对流层延迟误差改正类的提示信息
    cout << "/* 测试对流层延迟误差改正类 */" << endl;
    // 创建对流层延迟误差改正类对象
    TroposphereCorrection tropoCorrection;
    // 调用对流层延迟误差改正类的测试函数
    tropoCorrection.test();

    /* 测试C01卫星的延迟改正值 */
    /* 测试C01卫星的延迟改正值 */
    XYZ receiverPos = { -2091342.6543, 4800418.4462, 3629758.3665 }; // 接收机坐标
    XYZ satellitePos = ps1; // C01卫星坐标 
    
    double ionoDelay = ionoCorrection.calculateIonosphereDelayKlobuchar(tr, receiverPos, satellitePos);
    cout << "C01卫星电离层延迟改正值: " << ionoDelay << " 米" << endl;
    
    double tropoDelay = tropoCorrection.calculateTroposphereDelaySaastamoinen(tr, receiverPos, satellitePos);
    cout << "C01卫星对流层延迟改正值: " << tropoDelay << " 米" << endl;

    /* 测试单点定位类 */
    cout << "/* 测试单点定位类 */" << endl;
    PointPositioning pointPos;
    XYZ approxPos = { -2091342.6543, 4800418.4462, 3629758.3665 }; // 接收机近似坐标
    NavData navData = mReadN.ListBroadEph; // 获取导航数据
    XYZ finalPos = pointPos.calculatePosition(mObs->at(0), navData, approxPos);
    printf("最终定位结果: X=%.3f m, Y=%.3f m, Z=%.3f m\n", finalPos.x, finalPos.y, finalPos.z);

    system("pause");
    return 0;
}
